<?php


namespace App\Http\Controllers\Admin;


use App\Enums\ExportEnum;
use App\Enums\RedisKeyEnum;
use App\Exceptions\BasicException;
use App\Services\Tools\ObsService;
use App\Http\Controllers\BaseController;
use App\Response\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

class ExportController extends BaseController
{
    /**
     * @api {get} /export/log-list 导出日志
     *
     * @apiGroup 订单管理
     *
     * @apiParam {int} page 第几页
     * @apiParam {int} page_size 每页显示条数
     *
     * @apiSuccessExample 成功响应
     *  {
    "code": 200,
    "data": {
    "current_page": 1,
    "data": [
    {
    "id": 9, 序号
    "title": "用户充值列表", 标题
    "status": 1, 状态 0：未完成；1：导出成功；2：导出失败
    "download_url": "http://yutangyuyin1.oss-cn-hangzhou.aliyuncs.com/data_excel/20210803172406336用户充值.xls", 下载链接
    "created_at": "2021-08-03 17:23:57", 预约时间
    "updated_at": "2021-08-03 17:24:07" 完成时间
    }
    ],
    "first_page_url": "http://local.qipaoadmin/export/log-list?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "http://local.qipaoadmin/export/log-list?page=1",
    "next_page_url": null,
    "path": "http://local.qipaoadmin/export/log-list",
    "per_page": 10,
    "prev_page_url": null,
    "to": 3,
    "total": 3
    }
    }
     */
    public function logList(Request $request)
    {
        $param = $request->only('page', 'page_size');
        //参数校验
        $v = app('validator')->make($param,
            [
                'page' => 'integer|min:1',
                'page_size' => 'integer|min:1|max:100',
            ]);
        if ($v->fails()) throw new BasicException(10001, $v->errors()->first());

        $pageSize = $param['page_size'] ?? 10;

        $list = app('model_admin_export_log')
            ->select('id', 'title', 'status', 'download_url', 'created_at', 'updated_at')
            ->where('admin_id', $request->admin_id)
            ->orderBy('id', 'desc')
            ->paginate($pageSize);
        return Response::sendData($list);
    }

    /**
     * @api {get} /export/user-recharge 导出用户充值
     *
     * @apiGroup 订单管理
     *
     * @apiParam {int} pay_type 支付方式
     * @apiParam {string} pay_channel 支付渠道
     * @apiParam {int} pay_status 支付状态：0：不限制（默认）；1：未支付；2：已支付
     * @apiParam {int} user_code 用户编号
     * @apiParam {string} order_sn 订单编号
     * @apiParam {string} trade_no 交易号
     * @apiParam {string} add_time_start 创建时间开始，yyyy-mm-dd，必须
     * @apiParam {string} add_time_end 创建时间结束，yyyy-mm-dd，必须
     * @apiParam {string} pay_time_start 支付时间开始，yyyy-mm-dd
     * @apiParam {string} pay_time_end 支付时间结束，yyyy-mm-dd
     * @apiParam {string} receive_account 收款账户类型
     *
     * @apiSuccessExample 成功响应
     *  导出一个xls的充值数据表格
     */
    public function userRecharge(Request $request)
    {
        $param = $request->only('pay_type', 'pay_channel', 'pay_status', 'user_code', 'order_sn', 'trade_no', 'add_time_start', 'add_time_end', 'pay_time_start', 'pay_time_end', 'receive_account', 'receive_account_name');
        //参数校验
        $v = app('validator')->make($param,
            [
                'pay_type' => 'integer',
                'pay_status' => 'integer|in:0,1,2',
                'user_code' => 'integer',
                'add_time_start' => 'required|date_format:Y-m-d',
                'add_time_end' => 'required|date_format:Y-m-d',
                'pay_time_start' => 'date_format:Y-m-d',
                'pay_time_end' => 'date_format:Y-m-d',
                'receive_account_name'=> 'string',
                'receive_account' => 'string',
            ]);
        if ($v->fails()) throw new BasicException(10001, $v->errors()->first());

        $addTimeStart = $param['add_time_start'] ?? '';
        $addTimeEnd = $param['add_time_end'] ?? '';

        if (strtotime($addTimeEnd) - strtotime($addTimeStart) > 2592000) {
            throw new BasicException(0, '创建时间范围必选，且跨度不能超过31天');
        }

        $logId = app('model_admin_export_log')->insertGetId([
            'title' => ExportEnum::NO[1]['desc_ch'],
            'admin_id' => $request->admin_id,
            'data_no' => 1,
            'condition' => json_encode($param),
        ]);
        if ($logId) {
            //加到队列
            app('redis')->lpush(RedisKeyEnum::ADMIN_EXPORT_LOG, $logId);
            return Response::sendData(['msg' => '预约导出成功，请前往 订单管理/充值订单导出日志 查看']);
        } else {
            throw new BasicException(0, '预约导出失败，请联系管理员');
        }
    }

    //生成用户充值数据（给定时任务调度）
    public function createUserRechargeData($exportLog = [])
    {
        ini_set('memory_limit', '1024M');

        $fields = [
            'id' => '用户id',
            'user_id' => '用户id',
            'user_code' => '用户编号',
            'nickname' => '用户昵称',
            'order_sn' => '订单编号',
            'trade_no' => '交易号',
            'money' => '充值金额',
            'gold' => '获得金币数',
            'pay_type' => '付款方式',
            'add_time' => '创建时间',
            'pay_time' => '付款时间',
            'pay_status' => '付款状态',
            'merchant_name' => '收款账户',
        ];
        //获取表头
        $headers = array_values($fields);

        //每个xls文件保存数据大小，单位：行
        $fileSize = 60000;

        //创建存放xls文件的目录
        $saveDir = $exportLog['title'] . '_' . date('YmdHis') . '_' . $exportLog['admin_id'];
        $savePath = storage_path('app/export/') . $saveDir;
        mkdir($savePath,0777,true);

        for ($i = 1; $i <= 10; $i++) {

            //1.查询数据（orm对象）
            $offset = ($i - 1) * $fileSize;
            $data = app('repo_user_recharge')->getExportList(json_decode($exportLog['condition'], true), $offset, $fileSize);
            if (count($data) == 0) break;
            //2.组装数据
            $content = "";
            $content .= "<table border='1'><tr>";

            //输出表头
            foreach ($headers as $v) {
                $content .= "<td>$v</td>";
            }
            $content .= "</tr>";

            //输出数据
            foreach ($data as $v) {
                $content .= "<tr>";
                foreach ($fields as $fieldKey => $fieldName) {
                    $content .= "<td style='vnd.ms-excel.numberformat:@'>" . $v->$fieldKey . "</td>";
                }
                $content .= "</tr>";
            }
            $content .= "</table>";

            //3.将数据保存到xls文件
            $file = $savePath . "/{$i}.xls";
            $fh = fopen($file, 'w');
            fputs($fh, $content);
            fclose($fh);
        }

        //压缩存放xls文件的目录
        $res = $this->createZipFile($savePath, $savePath . '.zip');
        if (!$res) {
            //todo 记录日志
//            Log::notice('导出文件压缩失败');
            //删除目录
            $this->rmDir($savePath);
            //导出失败
            $this->exportFailed($exportLog);
            return;
        }

        //压缩文件上传到oss
        $url = $this->uploadToOss($savePath . '.zip');
        if ($url) {
            app('model_admin_export_log')
                ->where('id', $exportLog['id'])
                ->update(['status'=> 1, 'download_url' => $url]);
        } else {
            //todo 记录日志
//            Log::notice('导出文件上传到oss失败');
            //导出失败
            $this->exportFailed($exportLog);
        }
        //删除导出文件目录
        $this->rmDir($savePath);
    }

    /**
     * 压缩
     * @param string $dir 要压缩的目录，绝对路径
     * @param string $zipFilename 压缩文件的名称，绝对路径
     * @return bool
     */
    private function createZipFile($path, $zipFilename)
    {
        $flag = false;
        $zip = new \ZipArchive;
        if ($zip->open($zipFilename, \ZipArchive::CREATE) === true) {
            $handle = opendir($path);
            while ($file = readdir($handle)) {
                if (is_file($path . '/' . $file)) {
                    $flag = true;
                    $zip->addFile($path . '/' . $file, $file);
                }
            }
            $zip->close();
        }
        return $flag;
    }

    /**
     * 压缩文件上传到oss
     * @param string $file 压缩文件，绝对路径
     * @return bool
     */
    private function uploadToOss($file)
    {
        $filename = basename($file);
        $target = 'admin/export/' . $filename; //oss保存路径
        $uploadRes = ObsService::putObs($target,$file);
        if ($uploadRes) {
            unlink($file); //删除压缩文件
            $url =  env('OBS_HOST') .'/';
            return $url . $target;
        } else {
            return '';
        }
    }

    /**
     * 删除目录及里面的文件
     * @param string $dirName 目录完整路径
     */
    private function rmDir($path)
    {
        if ($handle = opendir( $path)) {
            while ($file = readdir($handle)) {
                if ($file != '.' && $file != '..') {
                    unlink("$path/$file");
                }
            }
        }
        closedir( $handle );
        //删除目录
        rmdir($path);
    }

    private function exportFailed($exportLog)
    {
        app('model_admin_export_log')
            ->where('id', $exportLog['id'])
            ->update(['status'=> 2]);
    }
}